import java.util.HashMap;

public class PSInterpreter {

	private IStack<Object> stack;
	private HashMap<String, Float> symbols;
	
	private IStack<Object> printedQueue;
	

	public PSInterpreter(){
		stack = new DNodeStack<Object>();
		printedQueue = new DNodeQueue<Object>();
		symbols = new HashMap<String, Float>();
	}

	public void EvalQueue(IStack<String> queue){
		String defining = "";
		int definedSince = 0;

		try {
			while(!queue.isEmpty()){
				if(!defining.isEmpty()){
					definedSince++;
				}

				if(definedSince > 2){
					defining = "";
				}

				String token = queue.pop();
				if(isNumeric(token)){
					stack.push(Float.parseFloat(token));
				} else if(token.startsWith("/")){
					defining = token.replace("/", "");
				} else if(token.equals("def")){
					if(!defining.isEmpty()){
						symbols.put(defining, (Float) stack.pop());
					}
				} else if(token.equals("pstack")){
					printedQueue = stack.copyToStack(printedQueue);
				} else if (symbols.containsKey(token)){
					stack.push(symbols.get(token));
				} else {
					treatSymbol(token);
				}
			}
		} catch (NumberFormatException e){
			e.printStackTrace();
		} catch (EmptyStackException e) {
			e.printStackTrace();
		}
	}

	private void treatSymbol(String token) throws EmptyStackException {
		Float buffer = null;
		if(token.equals("add")){
			buffer = (Float) stack.pop() + (Float) stack.pop();
		} else if(token.equals("sub")){
			Float x = (Float) stack.pop();
			Float y = (Float) stack.pop();
			buffer = y - x;
		} else if(token.equals("mul")){
			buffer = (Float) stack.pop() * (Float) stack.pop();
		} else if(token.equals("div")){
			Float x = (Float) stack.pop();
			Float y = (Float) stack.pop();
			buffer = y / x;
		} else if(token.equals("dup")){
			stack.push(stack.top());
		} else if(token.equals("exch")){
			Object temp = stack.pop();
			Object temp2 = stack.pop();
			stack.push(temp);
			stack.push(temp2);
		} else if(token.equals("eq")){
			stack.push(stack.pop().equals(stack.pop()));
		} else if(token.equals("ne")){
			stack.push(! stack.pop().equals(stack.pop()));
		} else if(token.equals("pop")){
			stack.pop();
		} else {
			System.err.println(token + " is not a valid MiniPostScript Token. It will be ignored");
		}
		
		if(buffer != null){
			stack.push(buffer);
		}
	}

	public static boolean isNumeric(String str) {
		if (str == null) {
			return false;
		}
		int sz = str.length();
		for (int i = 0; i < sz; i++) {
			if ((Character.isDigit(str.charAt(i)) || str.charAt(i) == '.' || str.charAt(i) == '-') == false) {
				return false;
			}
		}
		return true;
	}
	
	public IStack<Object> getPrintedQueue(){
		return printedQueue;
	}
}
